#include "FileSection.h"
#include<vector>
#include"utils.h"

FileSection::FileSection(){
}


FileSection::~FileSection(){
	for(unsigned int i=0;i<chunks.size();i++){
		delete chunks[i];
	}

	chunksMapping.clear();
}



void FileSection::initChunkForReading(void){
	long filePosition=ftell(file->file);
	int pointerToChunkTable=file->readInt();
	filePosition=ftell(file->file);
	file->seek(pointerToChunkTable);
	int chunksCount=file->readShort();
	for(int i=0;i<chunksCount;i++){
		filePosition=ftell(file->file);
		wstring name=file->readString();
		filePosition=ftell(file->file);
		int pointer=file->readInt();
		filePosition=ftell(file->file);
		unsigned char byte=file->readByte();
		filePosition=ftell(file->file);
		HikariChunkType::ChunkType chunkType=(HikariChunkType::ChunkType)byte;
		Chunk*chunk=new Chunk(name, pointer, chunkType);
		chunks.push_back(chunk);
		chunksMapping[Utils::hash_WString(name)]=chunk;
	}
}

Chunk* FileSection::getChunk(const wstring&name){
	return chunksMapping[Utils::hash_WString(name)];
}

vector<Chunk*>FileSection::getAllSections(){
	vector<Chunk*>sections;
	for(unsigned int i=0;i<chunks.size();i++){
		if(chunks[i]->getChunkType()==HikariChunkType::SECTION){
			sections.push_back(chunks[i]);
		}
	}
	return sections;
}

vector<Chunk*>FileSection::getAllAttributes(){
	vector<Chunk*>sections;
	for(unsigned int i=0;i<chunks.size();i++){
		if(chunks[i]->getChunkType()!=HikariChunkType::SECTION){
			sections.push_back(chunks[i]);
		}
	}
	return sections;
}

string formatErrorMessage(HikariChunkType::ChunkType desiredType, HikariChunkType::ChunkType currentType){
	char buffer[1000];
	sprintf(buffer, "Error. Trying to read %s from chunk of the type %s", Chunk::toString(desiredType).c_str(), Chunk::toString(currentType).c_str());
	return string(buffer);
}

FileSection*FileSection::readSection(Chunk*chunk){
	if(chunk->getChunkType()!=HikariChunkType::SECTION){
		string message=formatErrorMessage(HikariChunkType::SECTION, chunk->getChunkType());
		throw message;
	}

	file->seek(chunk->getPointer());
	FileSection*newFileSection=new FileSection();
	newFileSection->file=file;
	newFileSection->setSectionName(chunk->getName());
	newFileSection->initChunkForReading();
	return newFileSection;
}

wstring FileSection::readString(Chunk*chunk){
	if(chunk->getChunkType()!=HikariChunkType::STRING){
		string message=formatErrorMessage(HikariChunkType::STRING, chunk->getChunkType());
		throw message;
	}

	file->seek(chunk->getPointer());
	return file->readString();
}

int FileSection::readInt(Chunk*chunk){
	if(chunk->getChunkType()!=HikariChunkType::INTEGER){
		string message=formatErrorMessage(HikariChunkType::INTEGER, chunk->getChunkType());
		throw message;
	}

	file->seek(chunk->getPointer());
	return file->readInt();
}

irr::video::SColor colorFromLong(long value){
	long mask = 0xFF;
	int blue = (int) (value & mask);
	int green = (int) ((value >> 8) & mask);
	int red = (int) ((value >> 16) & mask);
	int alpha = (int) ((value >> 24) & mask);
	irr::video::SColor color(alpha, red, green, blue);
	return color;
}

irr::video::SColor FileSection::readSColor(Chunk*chunk){
	if(chunk->getChunkType()!=HikariChunkType::SCOLOR){
		string message=formatErrorMessage(HikariChunkType::SCOLOR, chunk->getChunkType());
		throw message;
	}
	file->seek(chunk->getPointer());
	long value = (long)file->readLong();
	irr::video::SColor color=colorFromLong(value);
	return color;
}

irr::core::vector3df FileSection::readVector(Chunk*chunk){
	if(chunk->getChunkType()!=HikariChunkType::VECTOR){
		string message=formatErrorMessage(HikariChunkType::VECTOR, chunk->getChunkType());
		throw message;
	}
	file->seek(chunk->getPointer());
	float x=file->readFloat();
	float y=file->readFloat();
	float z=file->readFloat();
	irr::core::vector3df vector(x, y, z);
	return vector;
}

irr::core::dimension2df FileSection::readDimension2df(Chunk*chunk){
	if(chunk->getChunkType()!=HikariChunkType::DIMENSION2D){
		string message=formatErrorMessage(HikariChunkType::DIMENSION2D, chunk->getChunkType());
		throw message;
	}
	file->seek(chunk->getPointer());
	float w=file->readFloat();
	float h=file->readFloat();
	irr::core::dimension2df dim(w, h);
	return dim;
}

short FileSection::readShort(Chunk*chunk){
	if(chunk->getChunkType()!=HikariChunkType::SHORT){
		string message=formatErrorMessage(HikariChunkType::SHORT, chunk->getChunkType());
		throw message;
	}
	file->seek(chunk->getPointer());
	short value=file->readShort();
	return value;
}

long long FileSection::readLong(Chunk*chunk){
	if(chunk->getChunkType()!=HikariChunkType::LONG){
		string message=formatErrorMessage(HikariChunkType::LONG, chunk->getChunkType());
		throw message;
	}
	file->seek(chunk->getPointer());
	long long value=file->readLong();
	return value;
}


vector<long long> FileSection::readLongs(Chunk*chunk){
	if(chunk->getChunkType()!=HikariChunkType::ARRAY_OF_LONG){
		string message=formatErrorMessage(HikariChunkType::ARRAY_OF_LONG, chunk->getChunkType());
		throw message;
	}
	file->seek(chunk->getPointer());
	int count=file->readShort();
	vector<long long>longs;
	for(int i=0;i<count;i++){
		long long value=file->readLong();	
		longs.push_back(value);
	}
	
	return longs;
}

vector<bool> FileSection::readBooleans(Chunk*chunk){
	if(chunk->getChunkType()!=HikariChunkType::ARRAY_OF_BOOLEANS){
		string message=formatErrorMessage(HikariChunkType::ARRAY_OF_BOOLEANS, chunk->getChunkType());
		throw message;
	}
	file->seek(chunk->getPointer());
	int count=file->readShort();
	vector<bool>values;
	for(int i=0;i<count;i++){
		bool value=file->readBool();
		values.push_back(value);
	}
	
	return values;
}

bool FileSection::readBoolean(Chunk*chunk){
	if(chunk->getChunkType()!=HikariChunkType::BOOLEAN){
		string message=formatErrorMessage(HikariChunkType::BOOLEAN, chunk->getChunkType());
		throw message;
	}
	file->seek(chunk->getPointer());
	bool value=file->readBool();
	return value;
}

char FileSection::readChar(Chunk*chunk){
	if(chunk->getChunkType()!=HikariChunkType::CHAR){
		string message=formatErrorMessage(HikariChunkType::CHAR, chunk->getChunkType());
		throw message;
	}
	file->seek(chunk->getPointer());
	char value = (char)file->readChar();
	return value;
}

unsigned char FileSection::readByte(Chunk*chunk){
	if(chunk->getChunkType()!=HikariChunkType::BYTE){
		string message=formatErrorMessage(HikariChunkType::BYTE, chunk->getChunkType());
		throw message;
	}
	file->seek(chunk->getPointer());
	unsigned char value = file->readByte();
	return value;
}

float FileSection::readFloat(Chunk*chunk){
	if(chunk->getChunkType()!=HikariChunkType::FLOAT){
		string message=formatErrorMessage(HikariChunkType::FLOAT, chunk->getChunkType());
		throw message;
	}
	file->seek(chunk->getPointer());
	float value = file->readFloat();
	return value;
}

double FileSection::readDouble(Chunk*chunk){
	if(chunk->getChunkType()!=HikariChunkType::DOUBLE){
		string message=formatErrorMessage(HikariChunkType::DOUBLE, chunk->getChunkType());
		throw message;
	}
	file->seek(chunk->getPointer());
	double value = file->readDouble();
	return value;
}

